home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-05-18 | 55.6 KB | 1,936 lines |
- /* -*-C-*- dvialw.c */
- /*-->dvialw*/
- /**********************************************************************/
- /******************************* dvialw *******************************/
- /**********************************************************************/
-
- #include "dvihead.h"
-
- /***********************************************************************
- [23-Oct-87] Modify output so that on each page, fonts appear first,
- followed by "save ...text... restore" sequences.
- Current PostScript implementations on commercial
- printers lack garbage collection, and strings consume
- memory even after printing. The Apple LaserWriter and
- LaserWriter Plus have only about 100Kb free for each
- job, which at current memory prices is grossly
- inadequate. Other PostScript printer vendors are
- offering substantially more memory.
-
- This feature is implemented not by time-consuming double
- passes through the DVI file, but rather by having
- setchar() and setstr() buffer their output, which is
- dumped (with bracketing save/restore commands) either
- when the buffer fills up, or when end-of-page is
- reached. A buffer of 8Kb is adequate for this purpose
- (based on a 100-page document (dvidriver.ltx) producing
- a .dvi-alw file of 830Kb, of which 163Kb was font
- definitions, giving an average text requirement of
- 6.7Kb/page). These statistics were determined on Unix
- by
-
- awk '/^\[/,/^>/' foo.dvi-alw >foo.tmp
- ls -l foo.*
-
- Awk extracts the font definitions into the file foo.tmp,
- and ls tells how big the files are. A similar test on
- pages from the TeXBook found some pages needing up to
- 11Kb of text.
-
- Several new routines (putfontname(), text*()) and macros
- (OUT_*) are introduced to support these changes. Some
- care is needed when introducing new output sections to
- call OUT_IMMEDIATE or OUT_DEFERRED, as appropropriate.
- If this is not done, output will be in an incorrect
- order.
-
- Now that almost all output flows through a single
- routine, textchr(), it is possible to monitor the output
- to ensure that lines do not exceed PS_WIDTH. Text
- output for the \special{} command is an exception to
- this rule; it is transmitted exactly as found. Long
- comments are continued with a trailing "-" followed by
- "%-" on the next line. When textflush() empties the
- text buffer, newlines preceding "(" (the commonest case)
- are squeezed out, as long as this does not exceed the
- line width limit. Font changes are shortened to F#
- sequences, where # is the sequential number of the font
- (1,2,...) in the dvi file. F0 is reserved for a
- temporary font created inside a save/restore pair for a
- large character.
-
- Perhaps at some later date, we could sort the buffered
- text by font type, and minimize font changing.
-
- [10-Dec-86] Fix off-by-one error in value of y-offset output in
- character definition in loadchar(); this affects only
- the combination of rules with characters, such as LaTeX
- arrowheads. No other DVI drivers are affected by this.
-
- Fix off-by-one error in size of rule; this involves no
- code change here, only a change in dvialw.ps.
- Examination of output rules under high power magnifier
- shows that to draw a rule of width N dots, the bounding
- box should have a width of N-1 dots; the boundary counts
- toward the fill; this is not clear from the PostScript
- manual.
-
- [13-Jun-86] Fix special()--a short plot file could result in
- infinite loop in search for %%BoundingBox. Fixed
- openfont() to output requested magnification as well as
- substituted magnification.
-
- [19-Apr-86] Fix infinite loop in setstr(); BIGCHAR() forced exit
- from character collection loop on first iteration, and
- the current input character was stuffed back into the
- input buffer. A big character should just suppress
- downloading in the first loop.
-
- [12-Mar-86] Version 2.03 -- Major overhaul of PostScript output.
- Removed most explicit PostScript commands to header file
- dvialw.ps (in current directory), or if unavailable, the
- system file texinputs:dvialw.ps (defined by symbols
- PSDEF_PATH and PSDEF_FILE) which is copied to the output
- file by new procedure cppsfile(), stripped of comments
- and excess whitespace. References to these macros are
- output instead. This makes parameter twiddling and
- local customization much easier, and will allow users to
- obtain a variety of page formats and orientations by
- simple changes to personal copies of the header file.
- The header file is heavily commented and should be
- referred to for macro descriptions and an outline of the
- general PostScript document format produced by DVIALW.
-
- Removed variable-length argument lists to fatal() and
- warning() for portability. Changed all preprocessor
- #ifdef's and #ifndef's to #if's for portability; all
- symbols for devices, operating systems, and
- implementations are now explicitly defined to be 0 or 1.
-
- Added procedures fontfile() and fontsub() to encapsulate
- construction of system-dependent font file names and
- provide for user-specifiable font substitutions for
- unavailable font files.
-
- Fonts and character definitions are now encapsulated in
- compact macros. With help of Neal Holtz's DVI2PS and
- TEX.PS, figured out how to define fonts with origin
- along baseline, allowing output of several characters in
- a single command (except where roundoff would make TeX
- and PostScript positions disagree). New procedure
- setstr() handles this. Font scaling is now 1 for normal
- output, but can be changed to any other value if
- PostScript is to rescale the bitmaps (slow). Tests show
- a reduction of about 20% in total output file size.
- When PS_SHORTLINES is defined, character bitmaps are
- output one scan line per line, making them somewhat
- readable, and avoiding long lines. Leaving them as one
- long line could reduce the file size even further.
- Added support for LaTeX invisible fonts; if you send a
- bitmap of size 0 by 0 to the LaserWriter, all further
- fonts are printed as blanks until you cycle the power.
- No character definitions are loaded for such fonts.
-
- Made reloading of fonts for each page an option "-v"; it
- should now rarely be necessary. With large manuscripts,
- avoiding reloading cuts the space by 60% or more, and
- seems to be more successful at printing, averaging 30
- sec/page and 700-780 char/sec (close to limit of 960
- char/sec from 9600 baud serial line).
-
- Removed old #ifdef FOOBAR ... #endif code sections in
- several procedures which were completely obsolete.
- Added header comment line to every file; it contains the
- EMACS "-*-C-*-" mode string and the exact (case-sensive)
- filename, since many functions have been defined with
- names in mixed case for readability (probably should
- have used underscore instead, but none do), and on Unix,
- the letter case matters.
-
- Replaced index() and rindex(), which have different
- definitions in different C implementations, by 4.2BSD
- (and coming ANSI C standard) functions strchr() and
- strrchr(), for which .h files are provided.
-
- To further reduce the PostScript output size, PostScript
- interactive mode experiments determined that spaces are
- not required around parentheses, brackets, or braces,
- but ARE necessary between numbers and names. Thus the
- sequences
-
- [ <hexstring> # # # # # ] # D
- (string) # # S
-
- can be reduced to
-
- [<hexstring># # # # #]# D
- (string)# # S
-
- saving 4 and 1 characters respectively for each use of
- these commands. The PostScript file copy utility, LW78,
- already reduces CR LF pairs to LF, so in the interests
- of editability, we retain the former. Heavily-used
- macros have also been redefined with single letter
- names.
-
- [18-Jan-86] Version 2.02 -- Added macros to define new fonts (NF),
- set fonts (SF), and define characters (CH) in main.h,
- and use them in readfont.h and setchar(). Changed
- setchar() to skip character loading when character is
- not on page. Added setstr() to output several
- characters at a time, instead of using setchar() for
- each of them. These reduce the output file size
- considerably. Moved character bitmap output code into
- loadchar() where it should have been in the first place.
- Added test for output errors (usually because disk
- storage is exhausted) in main.h and prtpage.h.
-
- [20-Dec-85] Following recommendation of Allan Hetzel on LASER-LOVERS
- ARPA BBOARD, added "() pop" at top of every page. This
- selected by the switch PS_XONXOFFBUG:
-
- --------------------------------------------------------
- From: Allan Hetzel <SYSAL%UKCC.BITNET@WISCVM.ARPA>
- Subject: Re: Apple Laserwriter XON/XOFF problem
- To: <LASER-LOVERS@WASHINGTON.ARPA>
-
- The note posted to Laser-Lovers on Oct 28 by Joseph
- Goldstone of Symbolics Cambridge Research Center was
- helpful but I didn't try his suggested fix correctly and
- so I called Adobe. They were very helpful (much more so
- than Apple) and explained the problem and how to bypass
- it.
-
- My apologies to Adobe if this not an accurate
- description of the problem. The problem apparently is
- due to the PostScript interpreter getting confused by
- what it thinks is an excess of white space characters.
-
- The bypass is to place a special character (parenthesis,
- bracket, brace, slash, etc.) to the right of some token,
- but without an intervening white space character. As the
- PostScript scanner reads the token it also reads the
- special character which acts as a delimiter. The scanner
- then has to back up one character so that it can
- reprocess the special character after it has processed
- the preceding token. During this backing up process a
- number of internal values are recalculated, including
- some pointer into the input buffer. This causes the
- XON/XOFF protocol to work properly. Doing this once per
- page seems to keep everybody happy.
-
- Each page in the PostScript file built by our word
- processing program is surrounded by a "save restore"
- sequence. We changed the beginning save sequence
- "/saveobj save def" to read "/saveobj save def() pop".
- The "() pop" is effectively a no-op and we are assured
- that the necessary recalculations are done on each page.
- This seems to have corrected the problem completely.
-
- Allan Hetzel (sysal@ukcc.bitnet)
- --------------------------------------------------------
- ***********************************************************************/
-
- /**********************************************************************/
- /************************ Device Definitions ************************/
- /**********************************************************************/
-
- /* All output-device-specific definitions go here. This section must
- be changed when modifying a dvi driver for use on a new device */
-
- #undef POSTSCRIPT
- #define POSTSCRIPT 1 /* conditional compilation flag */
-
- #define PS_SIZELIMIT 150 /* characters larger than this */
- /* many dots high get loaded with */
- /* surrounding save/restore to */
- /* get around PostScript bugs */
-
- #undef PS_XONXOFFBUG
- #define PS_XONXOFFBUG 1 /* Allen Hetzel's XON/XOFF bug fix */
-
- #ifndef PS_SHORTLINES
- #define PS_SHORTLINES 0 /* run with long output lines */
- #endif
-
- #define VERSION_NO "2.10" /* DVI driver version number */
-
- #if PS_XONXOFFBUG
- #undef VERSION_NO
- #define VERSION_NO "2.10b" /* DVI driver version number */
- #endif
-
-
- #define DEVICE_ID "PostScript [Apple LaserWriter laser printer]"
- /* this string is printed at runtime */
-
- #define OUTFILE_EXT "alw"
-
- #define MAXPSLINE 80 /* longest line in PSDEF_FILE */
-
- #define PSDEF_PATH subpath /* pathname of system header file */
- #define PSDEF_FILE "dvialw.ps" /* name of header file */
-
- #define BYTE_SIZE 7 /* output file byte size */
-
- #undef STDRES
- #define STDRES 1 /* to get standard font resolution */
-
- #undef MAXOPEN
- #define MAXOPEN 12 /* limit on number of open files */
-
- #define MAXLINE 4096 /* maximum input file line size */
- /* it is needed only in special() */
-
- #define XDPI 300 /* horizontal dots/inch */
- #define XPSIZE 14 /* horizontal paper size in inches */
- /* (allow for landscape paper) */
- #define XSIZE (((XDPI*XPSIZE+2*HOST_WORD_SIZE-1)/\
- (2*HOST_WORD_SIZE))*(2*HOST_WORD_SIZE))
- /* number of horizontal dots; */
- /* MUST BE multiple of */
- /* 2*HOST_WORD_SIZE */
-
- #define YDPI 300 /* vertical dots/inch */
- #define YPSIZE 11 /* vertical paper size in inches */
- #define YSIZE (YDPI*YPSIZE) /* number of vertical dots */
-
-
- #if PS_SHORTLINES
-
- #ifndef PS_MAXWIDTH
- #define PS_MAXWIDTH 72 /* output never exceeds this width */
- #endif
-
- INT16 out_width; /* current line width */
-
- #endif /* PS_SHORTLINES */
-
- /***********************************************************************
- The following variables and macros implement the buffering of PostScript
- output so that output size can be reduced by removing unneeded
- separators, and so that a maximum line width can be enforced, except for
- code from special{}, which must be output verbatim.
-
- All PostScript output filters through textchr() at the lowest level, and
- on the basis of the `deferred' flag setting, it either defers output of
- its argument character by buffering it in textbuf[], or it outputs it
- immediately with putc().
-
- Because PostScript line breaking conventions are context sensitive,
- textchr() maintains static variables to keep track of the output state
- (comment, text, or string). It also handles all end-of-line
- translations, so \n can be used for end-of-line everywhere else.
-
- All output calls outside the text*() routines are done through macros
- OUT_*, and to shorten coding, OUT_NUM provides a trailing delimiting
- space.
-
- textbuf[] is allocated dynamically on the first call to devinit() so as
- not to consume space in the executable program disk file.
-
- textflush() is called by textchr() when textbuf[] fills up, and by
- eopact() at end-of-page.
-
- ***********************************************************************/
-
- #define MAXTEXT 16384 /* size of textbuf[] buffer */
-
- static char* textbuf = (char*)NULL; /* buffer for setchar() and setstr() */
- static char* ptext; /* next position in textbuf[] */
- static BOOLEAN deferred; /* deferred output status flag */
- static UNSIGN16 last_font_number; /* set by loadchar() */
-
- #if PS_SHORTLINES
- static BOOLEAN is_comment = FALSE;
- static BOOLEAN is_text = FALSE;
- static BOOLEAN is_string = FALSE;
- #endif /* PS_SHORTLINES */
-
- #define OUT_CHR(c) textchr((char)c)
-
- #define OUT_DEFERRED {deferred = TRUE;}
-
- #define OUT_FLT(fmt,flt) {\
- char s[25];\
- (void)sprintf(s,fmt,flt);\
- OUT_STR(s);}
-
- #define OUT_FONTNAME {\
- char s[11];\
- (void)sprintf(s,"F%d",fontptr->font_number);\
- OUT_STR(s);}
-
- #define OUT_IMMEDIATE {deferred = FALSE;}
-
- #define OUT_NL OUT_CHR('\n')
-
- #define OUT_NUM(n) textnum((long)(n))
-
- #define OUT_STR(s) textstr(s)
-
- #define OUT_XCHR(c) emitchar(c)
-
- #include "main.h"
- #include "abortrun.h"
- #include "actfact.h"
- #include "alldone.h"
-
- /*-->bopact*/
- /**********************************************************************/
- /******************************* bopact *******************************/
- /**********************************************************************/
-
- void
- bopact() /* beginning of page action */
- {
- INT16 page_number; /* TeX's \count0 parameter */
-
- page_number = (INT16)tex_counter[0];
-
- if (cur_page_number <= MAXPAGE)
- {
- (void)fflush(plotfp);
- page_loc[cur_page_number] = (long)FTELL(plotfp);
- page_tex[cur_page_number] = (INT32)page_number;
- }
- OUT_IMMEDIATE;
- OUT_STR("%%Page: ");
- OUT_NUM(page_number);
- OUT_NUM(cur_page_number);
- OUT_NL;
- if (ps_vmbug)
- OUT_STR("/SaveImage save def() pop\n");
- OUT_STR("BOP\n");
-
- rule_height = -1; /* reset last rule parameters */
- rule_width = -1;
- str_ycp = -1; /* last string ycp */
- }
-
- #include "chargf.h"
- #include "charpk.h"
- #include "charpxl.h"
- #include "clrrow.h"
-
- /*-->cppsfile*/
- /**********************************************************************/
- /****************************** cppsfile ******************************/
- /**********************************************************************/
-
- void
- cppsfile() /* Copy PostScript header file to output */
- { /* discarding comments and collapsing whitespace */
- register int c; /* input character */
- register int k; /* index in line[] */
- FILE *psfp; /* PostScript macro definition file */
- char fname[MAXFNAME];
- char line[MAXPSLINE+1]; /* extra space for NUL */
-
- /* Try private version of header file first, and if that fails, use */
- /* system version. Tell the user when a private version is selected. */
-
- OUT_IMMEDIATE;
- (void)strcpy(fname,PSDEF_FILE);
- psfp = fopen(fname,"r");
- DEBUG_OPEN(psfp,fname,"r");
- if (psfp == (FILE *)NULL)
- {
- (void)strcpy(fname,PSDEF_PATH);
- (void)strcat(fname,PSDEF_FILE);
- psfp = fopen(fname,"r");
- DEBUG_OPEN(psfp,fname,"r");
- if (psfp == (FILE *)NULL)
- {
- (void)sprintf(message,
- "cppsfile(): Cannot open PostScript definition file [%s]",
- fname);
- (void)fatal(message);
- }
- }
- else if (!quiet)
- {
- (void)fprintf(stderr,"[Using private PostScript definition file [%s]]",
- fname);
- NEWLINE(stderr);
- }
-
- k = 0;
- while ((c = getc(psfp)) != EOF)
- {
- if (c == '%') /* flush comments to (but not including) end-of-line */
- {
- while (((c = getc(psfp)) != EOF) && (c != '\n'))
- ; /* flush to end-of-line or end-of-file */
- c = '\n'; /* to force line output */
- line[k++] = '\n';
- }
- else if ((c == ' ') || (c == '\t') || (c == '\f'))
- { /* have whitespace */
- if (k) /* then not at beginning of line */
- line[k++] = ' '; /* so save only one blank */
- while (((c == ' ') || (c == '\t') || (c == '\f')) && (c != EOF))
- c = getc(psfp); /* discard following whitespace */
- ungetc(c,psfp); /* put back lookahead */
- }
- else if (c != '\r') /* save all but CR */
- line[k++] = (char)c;
-
- if ((c == '\n') || (c == EOF) || (k >= MAXPSLINE))
- {
- if (c == '\n') /* discard LF */
- k--;
- while ((k > 0) && (line[k-1] == ' ')) /* and trailing blanks */
- k--;
- line[k] = '\0';
- if (k > 0) /* non-empty line */
- {
- OUT_STR(line);
- OUT_NL;
- }
- k = 0;
- }
- }
-
- while ((k > 0) && (line[k-1] == ' ')) /* discard trailing blanks */
- k--;
- line[k] = '\0';
- if (k > 0) /* non-empty line */
- {
- OUT_STR(line);
- OUT_NL;
- }
-
- (void)fclose(psfp);
- }
-
- #include "dbgopen.h"
-
- /*-->devinit*/
- /**********************************************************************/
- /****************************** devinit *******************************/
- /**********************************************************************/
-
- void
- devinit(argc,argv) /* initialize device */
- int argc;
- char *argv[];
- {
- register INT16 k; /* loop index */
- char timestring[26]; /* "wkd mon dd hh:mm:ss 19yy\n" */
- long timeval; /* clock value from time() for ctime() */
-
- if (textbuf == (char*)NULL)
- { /* allocate textbuf[] only once */
- textbuf = (char*)MALLOC((unsigned)(MAXTEXT+1));
- if (textbuf == (char*)NULL)
- (void)fatal("Cannot allocate memory for textbuf[]");
- }
-
- ptext = textbuf;
-
- OUT_IMMEDIATE; /* need immediate output here */
- OUT_STR("%!\n"); /* magical file header */
- OUT_STR("%%Dimensions: 0 0 612 792\n"); /* 8.5 x 11 inch page size */
-
- OUT_STR("%%Title: ");
- OUT_STR(argv[0]); /* start of our command line */
- for (k = 1; k < (INT16)argc; ++k)
- {
- OUT_CHR(' ');
- OUT_STR(argv[k]);
- }
- OUT_NL; /* end of %%Title line */
-
- timeval = time((long*)NULL);
- (void)strcpy(timestring,ctime(&timeval));
- timestring[24] = '\0'; /* kill stupid \n from ctime() */
-
- OUT_STR("%%CreationDate: ");
- OUT_STR(timestring);
- OUT_NL;
- OUT_STR("%%Creator: ");
- OUT_STR((cuserid((char*)NULL) == (char*)NULL) ? "" : cuserid((char*)NULL));
- OUT_STR(" and [TeX82 DVI Translator Version ");
- OUT_STR(VERSION_NO);
- OUT_STR(" for ");
- OUT_STR(DEVICE_ID);
- OUT_NL;
-
- OUT_STR("%%Pages: (atend)\n");
-
- if (ps_vmbug)
- {
- OUT_STR("%%BugHistory: Incorporates save/restore and font");
- OUT_STR(" reloading for each page as PS Version 23.0");
- OUT_STR(" \"VM error\" bug workaround\n");
- }
-
- #if PS_XONXOFFBUG
- OUT_STR("%%BugHistory: Incorporates Allan Hetzel\'s 31-Oct-85");
- OUT_STR(" DARPA LASER-LOVERS PS Version 23.0 X-on/X-off");
- OUT_STR(" bug workaround\n");
- #endif /* PS_XONXOFFBUG */
-
- OUT_STR("%%EndComments\n");
- OUT_STR("%%EndProlog\n");
- font_switched = TRUE;
-
- (void)cppsfile(); /* copy standard PostScript definitions */
-
- OUT_STR("TeXdict begin\n");
- OUT_STR("BOJ\n");
-
- /* TB and TE (Text Begin and Text End) are save/restore sequences;
- they are used when textflush() has to empty its current buffer. */
-
- OUT_STR("/TB {save} bdf\n");
- OUT_STR("/TE {restore} bdf\n");
-
- #if 0
- OUT_STR("/TE {currentpoint 3 -1 roll restore moveto} bdf\n");
- #endif
-
- /* BB and BE (Big character Begin and End) are save/restore
- sequences that create a temporary font and set a character
- inside a save/restore pair. */
- OUT_STR("/BB {save /F0 NF 1 /F0 SF} bdf\n");
- OUT_STR("/BE {restore} bdf\n");
-
- font_count = 0; /* no font numbers are assigned yet */
- }
-
- /*-->devterm*/
- /**********************************************************************/
- /****************************** devterm *******************************/
- /**********************************************************************/
-
- void
- devterm() /* terminate device */
- {
- register INT16 k; /* loop index */
-
- OUT_IMMEDIATE;
- OUT_STR("EOJ\n");
- OUT_STR("%%Trailer\n");
- OUT_STR("%%Pages: ");
- OUT_NUM(page_count);
- OUT_NL;
- OUT_STR("%%PageTable: ");
-
- for (k = 1; k <= MIN(MAXPAGE,cur_page_number); ++k)
- {
- OUT_NUM(page_tex[k]);
- OUT_NUM(k);
- OUT_NUM(page_loc[k]);
- }
-
- OUT_NL;
- OUT_CHR('\004'); /* PostScript end-of-job signal */
- }
-
- #include "dvifile.h"
- #include "dviinit.h"
- #include "dviterm.h"
-
- /*-->emitchar*/
- /**********************************************************************/
- /****************************** emitchar ******************************/
- /**********************************************************************/
-
- void
- emitchar(c) /* output string character with */
- register BYTE c; /* escapes and octal as necessary */
- {
-
- /* we do our own octal formatting for speed */
- static char octalchars[] = "01234567";
-
- #define OCTAL(b) octalchars[((b) & 07)]
-
- #if PS_SHORTLINES
- if (!deferred && ((out_width + 4) >= (PS_MAXWIDTH-1)))
- {
- OUT_CHR('\\'); /* PostScript ignores */
- OUT_NL; /* backslash-newline sequences */
- }
- #endif /* PS_SHORTLINES */
-
- if (isprint(c) &&
- /* [textchr() requires the following restrictions] */
- !((c == ' ' ) || (c == '%') || (c == '(') || (c == ')') ||
- (c == '<') || (c == '>'))) /* character is printable */
- {
- if (c == '\\') /* double backslashes */
- OUT_CHR('\\');
- OUT_CHR(c);
- }
- else /* use octal form */
- {
- OUT_CHR('\\');
- OUT_CHR(OCTAL(c >> 6));
- OUT_CHR(OCTAL(c >> 3));
- OUT_CHR(OCTAL(c));
- }
- }
-
- /*-->eopact*/
- /**********************************************************************/
- /******************************* eopact *******************************/
- /**********************************************************************/
-
- void
- eopact() /* end of page action */
- {
- register INT32 k; /* loop index */
-
- textflush(); /* output accumulated text */
- OUT_IMMEDIATE;
- OUT_NUM(copies);
- OUT_STR("EOP\n");
-
- if (ps_vmbug)
- {
- OUT_STR("SaveImage restore() pop\n");
- font_switched = TRUE;
- fontptr = hfontptr;
- while (fontptr != (struct font_entry *)NULL)
- {
- for (k = 0; k < NPXLCHARS; ++k)
- fontptr->ch[k].isloaded = FALSE;
- fontptr = fontptr->next;
- }
- }
-
- for (k = (INT32)copies; k; --k)
- OUTC('\f'); /* FF's for simple page accounting */
- }
-
- #include "f20open.h"
- #include "fatal.h"
-
- /*-->fillrect*/
- /**********************************************************************/
- /****************************** fillrect ******************************/
- /**********************************************************************/
-
- void
- fillrect(x,y,width,height)
- COORDINATE x,y,width,height; /* lower left corner, size */
-
- /***********************************************************************
- With the page origin (0,0) at the lower-left corner, draw a filled
- rectangle at (x,y).
-
- For most TeX uses, rules are uncommon, and little optimization is
- possible. However, for the LaTeX Bezier option, curves are simulated by
- many small rules (typically 2 x 2) separated by positioning commands.
- By remembering the size of the last rule set, we can test for the
- occurrence of repeated rules of the same size, and reduce the output by
- omitting the rule sizes. The last rule parameters are reset by the
- begin-page action in prtpage(), so they do not carry across pages.
-
- It is not possible to use relative, instead of absolute, moves in these
- sequences, without stacking rules for the whole page, because each rule
- is separated in the DVI file by push, pop, and positioning commands,
- making for an uncertain correspondence between internal (xcp,ycp)
- pixel page coordinates and external device coordinates.
- ***********************************************************************/
-
- {
- str_ycp = -1; /* invalidate string y coordinate */
-
- OUT_IMMEDIATE; /* because Q uses width and height saved */
- OUT_NUM(x); /* by B, we cannot use deferred output; */
- OUT_NUM(y); /* otherwise a TB B TE TB Q TE would fail */
- if ((height != rule_height) || (width != rule_width))
- {
- OUT_CHR('M');
- OUT_CHR(' ');
- OUT_NUM(width);
- OUT_NUM(height);
- OUT_CHR('B');
- OUT_CHR(' ');
- rule_width = width; /* save current rule parameters */
- rule_height = height;
- }
- else
- {
- OUT_CHR('Q');
- OUT_CHR(' ');
- }
- }
-
- #include "findpost.h"
- #include "fixpos.h"
- #include "fontfile.h"
- #include "fontsub.h"
- #include "getbytes.h"
- #include "getfntdf.h"
- #include "getpgtab.h"
- #include "inch.h"
- #include "initglob.h"
-
- /*-->loadchar*/
- /**********************************************************************/
- /****************************** loadchar ******************************/
- /**********************************************************************/
-
- void
- loadchar(c)
- register BYTE c;
- {
- void (*charyy)(); /* subterfuge to get around PCC-20 bug */
- register struct char_entry *tcharptr; /* temporary char_entry pointer */
-
- if ((c < FIRSTPXLCHAR) || (LASTPXLCHAR < c)) /* check character range */
- return;
-
- tcharptr = &(fontptr->ch[c]);
-
- if (!VISIBLE(tcharptr))
- return; /* do nothing for invisible fonts */
-
- if (fontptr != pfontptr)
- openfont(fontptr->n);
-
- if (fontfp == (FILE *)NULL) /* do nothing if no font file */
- return;
-
- tcharptr->isloaded = TRUE;
-
- clearerr(plotfp); /* VMS sets the error flag unexpectedly */
-
- OUT_IMMEDIATE;
- OUT_STR("[<");
-
- /* Bug workaround: PCC-20 otherwise jumps to charxx instead of *charxx */
- charyy = fontptr->charxx;
- (void)(*charyy)(c,outrow); /* output rasters */
-
- OUT_CHR('>');
- OUT_NUM(tcharptr->xoffp);
- OUT_NUM((tcharptr->yoffp)+1);
- OUT_NUM(tcharptr->wp);
- OUT_NUM(tcharptr->hp);
- OUT_FLT("%.7f]",(float)(tcharptr->tfmw)*conv)
- OUT_NUM(c);
- OUT_CHR('D');
-
- #if PS_SHORTLINES
- OUT_CHR(' ');
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- /* Because of the deferred output feature, we now need to remember
- the last font used, so on the next call, we know whether to
- issue another OUT_FONTNAME or not. font_switched is no longer
- sufficient.
- */
- last_font_number = fontptr->font_number;
-
- if (DISKFULL(plotfp))
- (void)fatal("loadchar(): Output error -- disk storage probably full");
- }
-
-
- #include "movedown.h"
- #include "moveover.h"
- #include "moveto.h"
-
- /*-->newfont*/
- /**********************************************************************/
- /****************************** newfont *******************************/
- /**********************************************************************/
-
- void
- newfont()
- {
- register UNSIGN16 the_char; /* loop index */
- char s[MAXSTR];
-
- for (the_char = FIRSTPXLCHAR; the_char <= LASTPXLCHAR; the_char++)
- fontptr->ch[the_char].isloaded = FALSE;
-
- font_count++;
- fontptr->font_number = font_count;
-
- OUT_IMMEDIATE;
-
- (void)sprintf(s,"/%s NF %% %s\n",putfontname(fontptr),
- fontptr->name);
- OUT_STR(s); /* declare new font for PostScript */
-
- (void)sprintf(s,"/F%d {1 /%s SF} bdf\n",
- fontptr->font_number,putfontname(fontptr));
- OUT_STR(s); /* compact shorthand for font changes */
- }
-
- #include "nosignex.h"
- #include "openfont.h"
- #include "option.h"
-
- /*-->outrow*/
- /**********************************************************************/
- /******************************* outrow *******************************/
- /**********************************************************************/
-
- void
- outrow(c,yoff) /* output img_row[] to device */
- BYTE c; /* current character value */
- UNSIGN16 yoff; /* offset from top row (0,1,...,hp-1) (UNUSED here) */
- {
- UNSIGN16 bytes_per_row; /* number of raster bytes to copy */
- register UNSIGN16 k; /* loop index */
- register UNSIGN32 *p; /* pointer into img_row[] */
- struct char_entry *tcharptr;/* temporary char_entry pointer */
- register BYTE the_byte; /* unpacked raster byte */
-
- /* we do our own hexadecimal formatting for speed */
- static char hexchars[] = "0123456789ABCDEF";
-
- #define NIBBLE(b) hexchars[(b) & 0x0f]
-
- tcharptr = &(fontptr->ch[c]); /* assume check for valid c has been done */
- bytes_per_row = (UNSIGN16)((tcharptr->wp) + 7) >> 3; /* wp div 8 */
- p = img_row; /* we step pointer p along img_row[] */
-
- for (k = bytes_per_row; k > 0; ++p)
- {
-
- the_byte = (BYTE)((*p) >> 24);
- OUT_CHR(NIBBLE(the_byte>>4));
- OUT_CHR(NIBBLE(the_byte));
- if ((--k) <= 0)
- break;
-
- the_byte = (BYTE)((*p) >> 16);
- OUT_CHR(NIBBLE(the_byte>>4));
- OUT_CHR(NIBBLE(the_byte));
- if ((--k) <= 0)
- break;
-
- the_byte = (BYTE)((*p) >> 8);
- OUT_CHR(NIBBLE(the_byte>>4));
- OUT_CHR(NIBBLE(the_byte));
- if ((--k) <= 0)
- break;
-
- the_byte = (BYTE)(*p);
- OUT_CHR(NIBBLE(the_byte>>4));
- OUT_CHR(NIBBLE(the_byte));
- if ((--k) <= 0)
- break;
- }
-
- #if PS_SHORTLINES
- /* line breaking handled by textchr() */
- #else
- k = 40 / MAX(1,bytes_per_row); /* rows per 80-character line */
- /* break after last row, or whenever an 80-character line has
- been filled up */
- if (((yoff+1) == tcharptr->hp) || (((yoff+1) % k) == 0))
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- }
-
- #include "prtpage.h"
-
- /*-->putfontname*/
- /**********************************************************************/
- /**************************** putfontname *****************************/
- /**********************************************************************/
-
- char*
- putfontname(font_ptr)
- register struct font_entry *font_ptr;
- /* Output TeX font name and magnification in form "cmr10_1500" as a
- unique PostScript font identifier */
- {
- register char* nameptr;
- register char* p;
- static char namebuf[MAXSTR];
-
- nameptr = &(font_ptr->n[0]);
- p = namebuf;
-
- while (*nameptr) /* make name with non-alphanumerics */
- { /* changed to underscore for PostScript */
- *p++ = isalnum(*nameptr) ? *nameptr : '_';
- nameptr++;
- }
-
- (void)sprintf(p,"_%d",(int)font_ptr->magnification);
-
- return (&namebuf[0]);
- }
-
- #include "readfont.h"
- #include "readgf.h"
- #include "readpk.h"
- #include "readpost.h"
- #include "readpxl.h"
- #include "reldfont.h"
- #include "rulepxl.h"
-
- /*-->setchar*/
- /**********************************************************************/
- /****************************** setchar *******************************/
- /**********************************************************************/
-
- void
- setchar(c, update_h)
- register BYTE c;
- register BOOLEAN update_h;
- {
- register struct char_entry *tcharptr; /* temporary char_entry pointer */
-
- /* BIGCHAR() and ONPAGE() are used here and in setstr() */
-
- #define BIGCHAR(t) ((t->wp > (COORDINATE)size_limit) ||\
- (t->hp > (COORDINATE)size_limit))
-
- #define ONPAGE(t) (((hh - t->xoffp + t->pxlw) <= XSIZE) \
- && (hh >= 0)\
- && (vv <= YSIZE)\
- && (vv >= 0))
-
- if (DBGOPT(DBG_SET_TEXT))
- {
- (void)fprintf(stderr,"setchar('");
- if (isprint(c))
- (void)putc(c,stderr);
- else
- (void)fprintf(stderr,"\\%03o",(int)c);
- (void)fprintf(stderr,"'<%d>) (hh,vv) = (%ld,%ld) font name <%s>",
- (int)c, (long)hh, (long)vv, fontptr->n);
- NEWLINE(stderr);
- }
-
- tcharptr = &(fontptr->ch[c]);
-
- moveto(hh,YSIZE-vv);
- if (ONPAGE(tcharptr))
- { /* character fits entirely on page */
- if (VISIBLE(tcharptr))
- {
- if (BIGCHAR(tcharptr))
- {
- /* always need absolute coordinates (save/restore causes */
- /* loss of updated position) */
- OUT_IMMEDIATE;
-
- #if PS_SHORTLINES
- /* line breaking handled by textchar() */
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- OUT_STR("BB");
-
- #if PS_SHORTLINES
- OUT_CHR(' ');
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- loadchar(c);
- OUT_CHR('(');
- OUT_XCHR(c);
- OUT_CHR(')');
- OUT_NUM(xcp);
- OUT_NUM(ycp);
- OUT_CHR('S');
-
- #if PS_SHORTLINES
- OUT_CHR(' ');
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- OUT_STR("BE");
-
- #if PS_SHORTLINES
- /* line breaking handled by textchar() */
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- tcharptr->isloaded = FALSE; /* 'unload' character */
- }
- else
- {
- if (!tcharptr->isloaded)
- {
- if ((font_switched) ||
- (fontptr->font_number != last_font_number))
- {
- OUT_IMMEDIATE;
- OUT_FONTNAME;
- }
- loadchar(c);
- }
- OUT_DEFERRED;
- if (font_switched)
- {
- OUT_FONTNAME;
- font_switched = FALSE;
- }
- OUT_CHR('(');
- OUT_XCHR(c);
- OUT_CHR(')');
- if (ycp != str_ycp)
- {
- OUT_NUM(xcp);
- OUT_NUM(ycp);
- OUT_STR("S\n");
- str_ycp = ycp;
- }
- else
- {
- OUT_NUM(xcp);
- OUT_STR("T\n");
- }
- }
-
- }
- }
- else if (DBGOPT(DBG_OFF_PAGE) && !quiet)
- { /* character is off page -- discard it */
- (void)fprintf(stderr,
- "setchar(): Char %c [10#%3d 8#%03o 16#%02x] off page.",
- isprint(c) ? c : '?',c,c,c);
- NEWLINE(stderr);
- }
-
- if (update_h)
- {
- h += (INT32)tcharptr->tfmw;
- hh += (COORDINATE)tcharptr->pxlw;
- hh = fixpos(hh-lmargin,h,conv) + lmargin;
- }
- }
-
- #include "setfntnm.h"
- #include "setrule.h"
-
- /*-->setstr*/
- /**********************************************************************/
- /******************************* setstr *******************************/
- /**********************************************************************/
-
- void
- setstr(c)
- register BYTE c;
- {
- register struct char_entry *tcharptr; /* temporary char_entry pointer */
- register BOOLEAN inside;
- COORDINATE xcp_start,ycp_start; /* starting coordinates of string */
- INT32 h0,v0; /* (h,v) at entry */
- COORDINATE hh0,vv0; /* (hh,vv) at entry */
- register UNSIGN16 k; /* loop index */
- UNSIGN16 maxstr; /* loop limit */
- UNSIGN16 nstr; /* number of characters in str[] */
- BOOLEAN save_font_switched; /* for saving font_switched value */
- BYTE str[MAXSTR+1]; /* string accumulator */
- BOOLEAN truncated; /* off-page string truncation flag */
-
- /*******************************************************************
- Set a sequence of characters in SETC_000 .. SETC_127 with a minimal
- number of PostScript print-string commands. These sequences tend to
- occur in long clumps in a DVI file, and setting them together
- whenever possible substantially decreases the PostScript overhead
- and the size of the output file. A sequence can be set as a single
- string if
-
- * TeX and PostScript coordinates of each character agree (always
- true since PostScript has high-precision character widths
- available; for non-PostScript devices, violation of this
- requirement can be detected if fixpos() changes hh, or if ycp
- != ycp_start), AND
-
- * each character is in the same font (this will always be true
- in a sequence from a DVI file), AND
-
- * each character fits within the page boundaries, AND
-
- * each character definition is already loaded, AND
-
- * each character is from a visible font, AND
-
- * each character bitmap extent is smaller than the size_limit
- (which is used to enable discarding large characters after
- each use in order to conserve virtual memory storage on the
- output device).
-
- Whenever any of these conditions does not hold, any string already
- output is terminated, and a new one begun. In order to avoid output
- of empty string requests, a flag "inside" is set when a string
- opener "(" is output, and unset when the string terminator ") x y S"
- or ") P" is output.
-
- Two output optimizations are implemented here. First, up to MAXSTR
- (in practice more than enough) characters are collected in str[],
- and any that require downloading are handled. Then the entire
- string is set at once, subject to the above limitations. Second, by
- recording the vertical page coordinate, ycp, in the global variable
- str_ycp (reset in prtpage() at begin-page processing), it is
- possible to avoid outputting y coordinates unnecessarily, since a
- single line of text will generally result in many calls to this
- function.
- *******************************************************************/
-
- #define BEGINSTRING {inside = TRUE;\
- xcp_start = xcp;\
- ycp_start = ycp;\
- OUT_CHR('(');}
-
- #define ENDSTRING {inside = FALSE;\
- OUT_CHR(')');\
- if (ycp == str_ycp)\
- {\
- OUT_NUM(xcp_start);\
- OUT_STR("T\n");\
- }\
- else\
- {\
- OUT_NUM(xcp_start);\
- OUT_NUM(ycp_start);\
- OUT_STR("S\n");\
- str_ycp = ycp;\
- }}
-
- #define OFF_PAGE (-32767) /* off-page coordinate value */
-
- inside = FALSE;
- truncated = FALSE;
- OUT_IMMEDIATE;
-
- hh0 = hh;
- vv0 = vv;
- h0 = h;
- v0 = v;
- save_font_switched = font_switched;
- nstr = 0;
-
- #if PS_SHORTLINES
- /* With deferred output, textflush() cannot do any output parsing,
- so to avoid long lines, we allow at most a string
- "(...)nnnnn nnnnn S" on one line. */
- maxstr = MIN(PS_MAXWIDTH-15,MAXSTR);
- #else
- maxstr = MAXSTR;
- #endif /* PS_SHORTLINES */
-
- while ((SETC_000 <= c) && (c <= SETC_127) && (nstr < maxstr))
- { /* collect character sequence and download needed fonts */
- tcharptr = &(fontptr->ch[c]);
-
- moveto(hh,YSIZE-vv);
-
- if (ONPAGE(tcharptr) && VISIBLE(tcharptr))
- { /* character fits entirely on page and is visible */
- if ((!tcharptr->isloaded) && (!BIGCHAR(tcharptr)))
- {
- if (font_switched ||
- (fontptr->font_number != last_font_number))
- {
- OUT_FONTNAME;
- font_switched = FALSE;
- }
- loadchar(c);
- }
- }
- /* update horizontal positions in TFM and pixel units */
- h += (INT32)tcharptr->tfmw;
- hh += (COORDINATE)tcharptr->pxlw;
- hh = fixpos(hh-lmargin,h,conv) + lmargin;
-
- str[nstr++] = c; /* save string character */
-
- c = (BYTE)nosignex(dvifp,(BYTE)1);
- }
-
- /* put back character which terminated the loop */
- (void)UNGETC((int)(c),dvifp);
-
- hh = hh0; /* restore coordinates at entry */
- vv = vv0;
- h = h0;
- v = v0;
-
- if (DBGOPT(DBG_SET_TEXT))
- {
- (void)fprintf(stderr,"setstr(\"");
- for (k = 0; k < nstr; ++k)
- {
- c = str[k];
- if (isprint(c))
- (void)putc(c,stderr);
- else
- (void)fprintf(stderr,"\\%03o",(int)c);
- }
- (void)fprintf(stderr,"\") (hh,vv) = (%ld,%ld) font name <%s>",
- (long)hh, (long)vv, fontptr->n);
- NEWLINE(stderr);
- }
-
- OUT_DEFERRED;
- font_switched = save_font_switched;
- if (font_switched)
- {
- OUT_FONTNAME;
- OUT_NL; /* string might not be visible */
- font_switched = FALSE;
- }
-
- for (k = 0; k < nstr; ++k)
- { /* now set the collected characters */
- c = str[k];
- tcharptr = &(fontptr->ch[c]);
- moveto(hh,YSIZE-vv);
-
- if (ONPAGE(tcharptr) && VISIBLE(tcharptr))
- { /* character fits entirely on page and is visible */
- if (tcharptr->isloaded) /* character already downloaded */
- {
- if (!inside)
- BEGINSTRING;
- OUT_XCHR(c);
- }
- else /* must be big character (others are already downloaded) */
- {
- if (inside)
- ENDSTRING; /* finish any open string */
- if (BIGCHAR(tcharptr))
- { /* Large character to be discarded. */
- /* Inside save/restore, updated current point */
- /* is lost, so we must force absolute positioning */
- /* by resetting str_ycp before and after setting */
- /* the character. */
- str_ycp = OFF_PAGE;
- OUT_IMMEDIATE;
-
- #if PS_SHORTLINES
- /* line breaking handled by textchar() */
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- OUT_STR("BB");
-
- #if PS_SHORTLINES
- OUT_CHR(' ');
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- loadchar(c);
- BEGINSTRING;
- OUT_XCHR(c);
- ENDSTRING;
- OUT_STR("BE");
-
- #if PS_SHORTLINES
- OUT_CHR(' ');
- #else
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- OUT_CHR(' ');
- OUT_DEFERRED;
- tcharptr->isloaded = FALSE; /* 'unload' character */
- str_ycp = OFF_PAGE;
- }
- }
- }
- else /* character does not fit on page -- output */
- { /* current string and discard the character */
- truncated = TRUE;
- if (inside)
- ENDSTRING;
- }
- /* update horizontal positions in TFM and pixel units */
- h += (INT32)tcharptr->tfmw;
- hh += (COORDINATE)tcharptr->pxlw;
- hh = fixpos(hh-lmargin,h,conv) + lmargin;
- }
- if (truncated && DBGOPT(DBG_OFF_PAGE) && !quiet)
- {
- (void)fprintf(stderr,"setstr(): Text [");
- for (k = 0; k < nstr; ++k)
- (void)fprintf(stderr,isprint(str[k]) ? "%c" : "\\%03o",str[k]);
- (void)fprintf(stderr,"] truncated at page boundaries.");
- NEWLINE(stderr);
- }
-
- if (inside) /* finish last string */
- ENDSTRING;
- }
-
- #include "signex.h"
- #include "skgfspec.h"
- #include "skipfont.h"
- #include "skpkspec.h"
-
- /*-->special*/
- /**********************************************************************/
- /****************************** special *******************************/
- /**********************************************************************/
-
- void
- special(s) /* process TeX \special{} string in s[] */
- register char *s;
- {
- char line[MAXLINE+2];
- FILE *specfile;
- BOOLEAN abspos;
- INT16 k;
- int llx,lly,urx,ury; /* must be int for sscanf() */
- struct stat statbuf; /* so fstat() can get file size */
-
- /***********************************************************************
- The TeX \special{} command is expected to look like
-
- \special{overlay filename} % absolute positioning
- or
- \special{include filename} % relative positioning
- or
- \special{insert filename} % relative positioning
-
- In the first case, the PostScript file to be included will be mapped
- onto the page at precisely the coordinates it specifies. In the other
- two cases, the upper-left corner of the bounding box will be placed at
- the current point. The PostScript file must then contain (usually near
- the start) a comment of the form
-
- %%BoundingBox: llx lly urx ury
-
- specifying the bounding box lower-left and upper-right coordinates in
- standard PostScript units (1/72 inch). Alternatively, if the comment
-
- %%BoundingBox: (atend)
-
- is found in the file, the last 1000 characters of the file will be
- searched to find a comment of the form:
-
- %%BoundingBox: llx lly urx ury
-
- If the PostScript file cannot be opened, or the \special{} command
- string cannot be recognized, or for relative positioning, the bounding
- box cannot be determined, a warning message is issued and the \special
- command is ignored.
-
- Otherwise, the section of the PostScript file between the comment lines
-
- %begin(plot)
- %end(plot)
-
- is copied to the output file surrounded by
-
- save
- 300 72 div 300 72 div scale % revert to standard 1/72 inch units
- (xcp(in 1/72in)-llx) (ycp(in 1/72in)-ury) translate % if relative positioning
- ...PostScript file contents...
- restore
-
- ***********************************************************************/
-
- clearerr(plotfp); /* VMS sets the error flag unexpectedly */
-
- if (strncmp("overlay ",s,8) == 0)
- {
- k = 8;
- abspos = TRUE;
- }
- else if (strncmp("include ",s,8) == 0)
- {
- k = 8;
- abspos = FALSE;
- }
- else if (strncmp("insert ",s,7) == 0)
- {
- k = 7;
- abspos = FALSE;
- }
- else
- {
- NEWLINE(stderr);
- (void)fprintf(stderr,
- "[TeX \\special{%s} command not understood]",s);
- NEWLINE(stderr);
- (void)fprintf(stderr,"Expected one of:");
- NEWLINE(stderr);
- (void)fprintf(stderr,
- "\t\\special{overlay filename} [relative to page origin in ");
- (void)fprintf(stderr,
- "lower-left corner]");
- NEWLINE(stderr);
- (void)fprintf(stderr,"or");
- NEWLINE(stderr);
- (void)fprintf(stderr,
- "\t\\special{insert filename} [relative to current position]");
- NEWLINE(stderr);
- (void)fprintf(stderr,"or");
- NEWLINE(stderr);
- (void)fprintf(stderr,
- "\t\\special{include filename} [relative to current position]");
- NEWLINE(stderr);
- (void)fprintf(stderr,"\\special{%s} request ignored",s);
- NEWLINE(stderr);
- (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
- NEWLINE(stderr);
- return;
- }
- specfile = fopen(&s[k],"r");
- DEBUG_OPEN(specfile,&s[k],"r");
- if (specfile == (FILE *)NULL)
- {
- NEWLINE(stderr);
- (void)fprintf(stderr,
- "Open failure on \\special file [%s]",&s[k]);
- NEWLINE(stderr);
- (void)fprintf(stderr,"\\special{%s} request ignored",s);
- NEWLINE(stderr);
- (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
- NEWLINE(stderr);
- return;
- }
- if (abspos)
- {
- llx = lly = 0;
- urx = (72*17)/2;
- ury = 72*11;
- }
- else
- {
- llx = lly = urx = ury = -1;
- while (fgets(line,MAXLINE,specfile) != (char *)NULL)
- {
- llx = lly = urx = ury = -1;
- if (strncmp(line,"%%BoundingBox: (atend)",22) == 0)
- { /* reposition to up to 1000 chars from end of file */
- (void)fstat(fileno(specfile),&statbuf);
- k = MIN(1000,(INT16)((long)statbuf.st_size-ftell(specfile)));
- if (k > 0)
- (void)fseek(specfile,(long)(-k),2);
- }
- else if (strncmp(line,"%%BoundingBox:",14) == 0)
- {
- k = (INT16)sscanf(line,
- "%%%%BoundingBox: %d %d %d %d",&llx,&lly,&urx,&ury);
- if (k == 4)
- break; /* got %%BoundingBox */
- }
- }
- }
- if (ury == (-1))
- {
- NEWLINE(stderr);
- (void)fprintf(stderr,
- "Could not find PostScript %%%%BoundingBox command ");
- (void)fprintf(stderr,"needed to position plot on page");
- NEWLINE(stderr);
- (void)fprintf(stderr,"\\special{%s} request ignored",s);
- NEWLINE(stderr);
- (void)fprintf(stderr,"Current TeX page counters: [%s]",tctos());
- NEWLINE(stderr);
- return;
- }
- NEWLINE(stderr);
- (void)fprintf(stderr,"\t[\\special{%s}] ",s);
- NEWLINE(stderr);
-
- OUT_IMMEDIATE;
- OUT_STR("save\n"); /* save current state */
-
- OUT_STR("300 72 div 300 72 div scale\n"); /* revert to standard units */
-
- if (!abspos) /* move origin for include/insert */
- {
- moveto(hh,YSIZE-vv); /* update current point */
- OUT_NUM((72*xcp)/300-llx);
- OUT_NUM((72*ycp)/300-ury);
- OUT_STR("translate\n");
- }
- (void)REWIND(specfile); /* rewind file */
-
- while (fgets(line,MAXLINE,specfile) != (char *)NULL)
- { /* search for %begin(plot) ... %end(plot) */
- if (strncmp(line,"%begin(plot)",12) == 0)
- { /* copy until %end(plot) */
- while (fgets(line,MAXLINE,specfile) != (char *)NULL)
- {
- if (strncmp(line,"%end(plot)",10) == 0)
- break;
- OUTS(line);
- }
- break;
- }
- }
- OUT_STR("restore\n");
- (void)fclose(specfile);
- if (!quiet)
- {
- (void)fprintf(stderr," [OK]");
- NEWLINE(stderr);
- }
- if (DISKFULL(plotfp))
- (void)fatal("special(): Output error -- disk storage probably full");
- }
-
- #include "strchr.h"
- #include "strcm2.h"
- #include "strid2.h"
- #include "strrchr.h"
- #include "tctos.h"
-
- /*-->textchr*/
- /**********************************************************************/
- /****************************** textchr *******************************/
- /**********************************************************************/
-
- void
- textchr(c) /* output character c */
- register char c;
- {
- char* psave;
-
- if (deferred) /* deferred output */
- {
- *ptext++ = c;
- if (ptext >= (textbuf + MAXTEXT))
- {
- /* textbuf[] is full. Backup to the last newline, output
- textbuf[] to that point, move the remainder to the
- start of textbf[], and resume character collection. */
- *ptext = '\0'; /* mark the end */
- psave = strrchr(textbuf,'\n'); /* find last line break */
- ptext = psave; /* shorten buffer */
- *ptext = '\0'; /* mark the new end */
- textflush(); /* output the buffer */
- ++psave; /* where we want to pick up remainder */
- OUT_FONTNAME; /* make sure current font starts buffer */
- OUT_NL;
- OUT_NUM(xcp); /* make sure current point is set too */
- OUT_NUM(ycp);
- OUT_STR("M\n");
-
- /* Since the above initial sequence requires at most 25
- characters, we should be safe here, since psave should
- be pointing near the end of textbuf[]. Nevertheless, we
- should watch for this time bomb, because someday someone
- might make MAXTEXT ridiculously small. */
- if (ptext > psave)
- fatal("textchr(): internal error--textbuf[] too small");
-
- (void)strcpy(ptext,psave); /* move remainder to start */
- ptext = strchr(textbuf,'\0'); /* find the new end again */
- }
- }
- else /* immediate output */
- {
-
- #if PS_SHORTLINES
- /***************************************************************
- Unfortunately, PostScript does allows only text bracketed by ()
- to be broken across lines by a \newline sequence. We must
- therefore continue comments manually and break <...> strings by
- a newline. emitchar() ensures that % in () and non-bracketing
- () <> are encoded in octal, so as not to confuse us here.
- ***************************************************************/
-
- switch (c) /* set flags for exiting environments */
- {
- case '\n':
- is_comment = FALSE;
- break;
-
- /* '<' editor balance */
- case '>':
- if (!is_comment)
- is_string = FALSE;
- break;
-
- /* '(' editor balance */
- case ')':
- if (!is_comment)
- is_text = FALSE;
- break;
- }
-
- if (out_width < (PS_MAXWIDTH-2)) /* 3 or more slots left on line */
- {
- switch (c)
- {
- case '\n':
- NEWLINE(plotfp);
- out_width = 0;
- break;
-
- default:
- OUTC(c);
- out_width++;
- break;
- }
- }
- else if (out_width == (PS_MAXWIDTH-2)) /* 2 slots left on line */
- {
- if (is_comment)
- {
- OUTC(c);
- out_width++;
- }
- else /* not comment */
- {
- switch (c)
- {
- case '(': /* special \newline inside (...text...) */
- OUTC(c);
- OUTC('\\');
- NEWLINE(plotfp);
- out_width = 0;
- break;
-
- case '\n': /* ordinary newline */
- NEWLINE(plotfp);
- out_width = 0;
- break;
-
- default: /* else just output the character */
- OUTC(c);
- out_width++;
- break;
- } /* end switch */
- } /* end if (is_comment) */
- }
- else /* at most 1 slot left */
- {
- if (is_comment)
- { /* make special continued comment */
- OUTC('-');
- NEWLINE(plotfp);
- OUTS("%-");
- OUTC(c);
- out_width = 3;
- }
- else /* not comment */
- {
- switch (c)
- {
- case '%': /* start newline for comment or (...text...) */
- case '(':
- NEWLINE(plotfp);
- OUTC(c);
- out_width = 1;
- break;
-
- case ')': /* follow (...text...) with newline */
- case '<': /* newline inside <...text...> okay */
- case '>': /* follow <...text...> with newline */
- OUTC(c);
- NEWLINE(plotfp);
- out_width = 0;
- break;
-
- case ' ': /* change trailing space to newline */
- case '\n': /* newline */
- NEWLINE(plotfp);
- out_width = 0;
- break;
-
- default:
- if (is_text) /* \newline continuation in (...text...) */
- {
- OUTC('\\');
- NEWLINE(plotfp);
- OUTC(c);
- out_width = 1;
- }
- else if (is_string) /* newline inside <...text...> okay */
- {
- OUTC(c);
- NEWLINE(plotfp);
- out_width = 0;
- }
- else /* cannot break at this point, sigh... */
- {
- OUTC(c);
- out_width++;
- }
- break;
- } /* end switch */
- } /* end if (is_comment) */
- }
-
- switch (c) /* set flags for entering environments */
- {
- case '%':
- is_comment = TRUE;
- break;
-
- case '<':
- if (!is_comment)
- is_string = TRUE;
- break;
-
- case '(':
- if (!is_comment)
- is_text = TRUE;
- break;
- }
- #else /* NOT PS_SHORTLINES */
- OUTC(c);
- #endif /* PS_SHORTLINES */
-
- } /* endif deferred/immediate */
- }
-
- /*-->textflush*/
- /**********************************************************************/
- /***************************** textflush ******************************/
- /**********************************************************************/
-
- void
- textflush() /* flush current textbuf[] to output */
- {
-
- #if PS_SHORTLINES
- register char* pbreak; /* point to character before */
- /* which we can insert a line break */
- char linebuf[PS_MAXWIDTH+1]; /* buffer for output line */
- register INT16 k; /* index in linebuf[] */
- register INT16 kbreak; /* break index in linebuf[] */
- /* corresponding to pbreak */
- #endif /* PS_SHORTLINES */
-
- /* Wrap the current textbuf[] contents with save/restore, but
- preserve the current point and font. */
- if (ptext > textbuf) /* make sure textbuf[] is not empty */
- {
-
- #if PS_SHORTLINES
- if (out_width > 0) /* want TB ... TE on separate lines */
- NEWLINE(plotfp);
- #endif /* PS_SHORTLINES */
-
- OUTS("TB");
- NEWLINE(plotfp);
-
- *ptext = '\0'; /* terminate current textbuf[] */
-
- #if PS_SHORTLINES
- ptext = textbuf;
- pbreak = ptext;
- k = 0;
- kbreak = 0;
- while (*ptext)
- {
- if (k >= PS_MAXWIDTH)
- {
- if (kbreak > 0)
- {
- k = kbreak;
- ptext = pbreak;
- }
- while ((k > 0) && (linebuf[k-1] == ' '))
- k--; /* trim trailing space */
- linebuf[k] = '\0';
- OUTS(linebuf);
- k = 0;
- if ((kbreak > 0) || (*(ptext+1) == '\0'))
- NEWLINE(plotfp);
- }
- if ((*ptext == '\n') && (*(ptext+1) == '('))
- ptext++; /* squeeze out useless newline */
- if (*ptext == '\n')
- *ptext = ' '; /* change newline to blank */
- if ((k == 0) && (*ptext == ' '))
- /* NO-OP */; /* don't save leading space */
- else
- linebuf[k++] = *ptext;
- if ((*ptext == ' ') || (*ptext == '('))
- {
- kbreak = k - 1;
- pbreak = ptext;
- }
- else if (*ptext == ')')
- {
- kbreak = k;
- pbreak = ptext + 1;
- }
- ptext++;
- }
- if (k > 0)
- {
- while ((k > 0) && (linebuf[k-1] == ' '))
- k--; /* trim trailing space */
- linebuf[k] = '\0';
- OUTS(linebuf);
- NEWLINE(plotfp);
- }
- out_width = 0;
- #else /* NOT PS_SHORTLINES */
- OUTS(textbuf);
- NEWLINE(plotfp);
- #endif /* PS_SHORTLINES */
-
- OUTS("TE");
- NEWLINE(plotfp);
-
- ptext = textbuf;
- }
- }
-
- /*-->textnum*/
- /**********************************************************************/
- /****************************** textnum *******************************/
- /**********************************************************************/
-
- void
- textnum(n) /* output number with one trailing space */
- long n; /* the number */
- {
- char digits[11];
-
- (void)sprintf(digits,"%ld",n);
- textstr(digits);
-
- #if PS_SHORTLINES
- if (!deferred && !is_comment && (out_width == 0))
- /* NO-OP */; /* omit space at beginning of line */
- else
- textchr(' ');
-
- #else /* NOT PS_SHORTLINES */
- textchr(' ');
- #endif /* PS_SHORTLINES */
-
- }
-
-
-
- /*-->textstr*/
- /**********************************************************************/
- /****************************** textstr *******************************/
- /**********************************************************************/
-
- void
- textstr(s) /* output string s[] */
- register char* s;
- {
-
- #if PS_SHORTLINES
- if (!deferred && !is_comment && ((out_width + strlen(s)) > PS_MAXWIDTH))
- OUT_NL;
- #endif /* PS_SHORTLINES */
-
- for (; *s; ++s)
- textchr(*s);
- }
-
- #include "usage.h"
- #include "warning.h"
-